import https from 'https'
import fs from 'fs'
import path from 'path'
import sharp from 'sharp'

var mkdirByPath = (targetDir, cb, { isRelativeToScript = false } = {}) => {
  targetDir = path.dirname(targetDir)
  const sep = path.sep
  const initDir = path.isAbsolute(targetDir) ? sep : ''
  const baseDir = isRelativeToScript ? __dirname : '.'

  targetDir.split(sep).reduce((parentDir, childDir) => {
    const curDir = path.resolve(baseDir, parentDir, childDir)
    fs.mkdir(curDir, function(err) {
      if (err) {
        if (err.code == 'EEXIST') cb(null)
        // ignore the error if the folder already exists
        else cb(err) // something else went wrong
      } else cb(null) // successfully created folder
    })

    return curDir
  }, initDir)
}

module.exports = {
  download: async (url, dest) => {
    return new Promise((resolve, reject) => {
      console.log(`downloading: ${url} to ${dest}`)
      mkdirByPath(dest, function(err) {
        if (err) {
          // handle folder creation error
          reject(err)
        } else {
          // we're all good
          var file = fs.createWriteStream(dest)
          https
            .get(url, function(response) {
              response.pipe(file)
              file.on('finish', function() {
                // close() is async, resolve after close completes.
                file.close(function() {
                  resolve(dest)
                })
              })
            })
            .on('error', function(err) {
              // Handle errors
              fs.unlink(dest) // Delete the file async. (But we don't check the result)
              reject(err)
            })
        }
      })
    })
  },

  stitchFixedTotalSizeCeil: (files, result) => {
    return new Promise((resolve, reject) => {
      try {
        // 1. get avatar list
        //        dir = dir.endsWith('/') ? dir : dir + '/'
        //        let files = fs.readdirSync(dir)
        files = files.filter(item => {
          return fs.existsSync(item) && fs.statSync(item).size != 0 // remove empty image
        })

        // 2. compute sizes
        /* Fixed Total Size: Ceil
                                size
                         —————————————————
                        |__|n             |
                        | n               |
                   size |                 |
                        |                 |
                        |                 |
                        |                 |
                         —————————————————
                */
        const size = 200
        let columns = Math.ceil(Math.sqrt(files.length))
        let rows = Math.ceil(files.length / columns)
        let eachsize = Math.floor(size / columns)
        let yOffset = Math.floor(((columns - rows) * eachsize) / 2)
        let xOffset = Math.floor(
          ((columns * rows - files.length) * eachsize) / 2
        )

        let x = 0
        let y = 0

        // 3. prepare for composite
        const options = {
          raw: {
            width: size,
            height: size,
            channels: 4
          }
        }
        const base = sharp({
          create: {
            width: size,
            height: size,
            channels: 4,
            background: { r: 192, g: 192, b: 192, alpha: 1 }
          }
        })
          .raw()
          .toBuffer()

        // 4. do images composite
        const composite = files.reduce(function(input, file) {
          return input.then(async function(data) {
            let temp = sharp(data, options)
              .overlayWith(
                await sharp(file)
                  .resize(eachsize, eachsize)
                  .toBuffer(),
              {
                top: eachsize * y + yOffset,
                left: eachsize * x + (y >= rows - 1 ? xOffset : 0)
              }
              )
              .raw()
              .toBuffer()
            x += 1
            if (x == columns) {
              x = 0
              y += 1
            }
            return temp
          })
        }, base)

        // data contains the multi-composited image as raw pixel data
        composite.then(function(data) {
          sharp(data, {
            raw: {
              width: size,
              height: size,
              channels: 4
            }
          }).toFile(result, function(err, output) {
            if (err) {
              console.log(err)
            }
            console.log(output)
            resolve(result)
          })
        })
      } catch (err) {
        reject(err)
      }
    })
  }
}
